package org.corlan {
	import flash.events.EventDispatcher;
	import flash.events.IEventDispatcher;
	import flash.events.TimerEvent;
	import flash.utils.Timer;
	
	import mx.collections.ArrayCollection;
	import mx.core.Singleton;
	
	import org.corlan.events.PlayerEvent;
	import org.corlan.peer2peer.MultiCastingService;
	import org.corlan.peer2peer.Utils;
	import org.corlan.peer2peer.events.ServiceEvent;
	
	[Event(name="connected", type="org.corlan.events.ServiceEvent")]
	[Event(name="disconnected", type="org.corlan.events.ServiceEvent")]
	[Event(name="peerdisconnect", type="org.corlan.events.ServiceEvent")]
	[Event(name="name", type="org.corlan.events.ServiceEvent")]
	//players event - from remote apps
	[Event(name="playlistchanged", type="org.corlan.events.PlayerEvent")]
	[Event(name="play", type="org.corlan.events.PlayerEvent")]
	[Event(name="pause", type="org.corlan.events.PlayerEvent")]
	[Event(name="setvolume", type="org.corlan.events.PlayerEvent")]
	
	public class PlayerRemoteEndPoint extends EventDispatcher {
		
		private static var instance:PlayerRemoteEndPoint;
		private var _currentPlayer:String;
		private var peerIDToPlayer:Object;

		[Bindable]
		public var players:ArrayCollection = new ArrayCollection();
		[Bindable]
		public var playList:ArrayCollection;
		
		private var service:MultiCastingService;
		private var timer:Timer = new Timer(200, 0);
		private var userName:String;
		private static const GROUP_NAME:String = "mp3playergroup";

		
		
		public function PlayerRemoteEndPoint(target:IEventDispatcher, clz:Singleton) {
			super(target);
			peerIDToPlayer = new Object();
			timer.addEventListener(TimerEvent.TIMER, onTimer);
			service = new MultiCastingService(null, true, GROUP_NAME);
			userName = service.userName;
			service.addEventListener(ServiceEvent.CONNECTED, onConnection, false, 0, true);
			service.addEventListener(ServiceEvent.DISCONNECTED, onLostConnection, false, 0, true);
			service.addEventListener(ServiceEvent.RESULT, onResult, false, 0, true);
			service.addEventListener(ServiceEvent.PEER_DISCONNECT, onPeerDisconnect, false, 0, true);
		}
		
		public static function getInstance(target:IEventDispatcher=null):PlayerRemoteEndPoint {
			if (!instance)
				instance = new PlayerRemoteEndPoint(target, new Singleton());
			return instance;
		}
		
		public function set currentPlayer(value:String):void {
			var r:Boolean = false;
			if (_currentPlayer != value) r = true;
			_currentPlayer = value;
			if (r) refreshPlaylist();
		}
		public function get currentPlayer():String {
			return _currentPlayer;
		}

		public function connect():void {
			service.connect();
		}
		
		public function disconnect():void {
			service.disconnect();
		}
		
		public function refreshPlaylist():void {
			service.post(null, PlayerEvent.GET_PLAYLIST, _currentPlayer, true);
		}
		
		public function getPlayers():void {
			service.post(null, ServiceEvent.GET_COMP_NAME, null, true);
		}
		
		//post(mess:Object, what:String, to:String=null)
		private function onResult(e:ServiceEvent):void {
			//trace(e.from + " | " + e.body.what + " | " + e.body.value.toString());
			if (e.from != _currentPlayer 
					&& e.what != ServiceEvent.COMP_NAME)
				return;
			if (e.from == userName)
				return;
			
			var playerEvent:PlayerEvent;
			
			trace("RECEIVE " + e.from + " | " + e.what + " | " + (e.body?e.body.toString():"") );
			switch(e.what) {
				case ServiceEvent.COMP_NAME:
					if (e.from == e.body) {
						if (!players.contains(e.from)) {
							players.addItem(e.from);
							peerIDToPlayer[e.peerID] = e.from;
						}
						dispatchEvent(new ServiceEvent(ServiceEvent.COMP_NAME));
					}
					break;
				case PlayerEvent.GET_PLAYLIST:
					var tmp:ArrayCollection = e.body as ArrayCollection;
					playList = new ArrayCollection();
					var item:Object;
					var song:SongVO;
					for (var i:int = 0, l:int = tmp.length; i<l; i++) {
						item = tmp.getItemAt(i);
						song = new SongVO();
						song.filename = item.filename;
						song.artist = item.artist;
						song.song = item.song; 
						playList.addItem(song);
					}
					service.post(null, PlayerEvent.PLAYING, _currentPlayer, true);
					playerEvent = new PlayerEvent(PlayerEvent.PLAYLIST_CHANGED);
					dispatchEvent(playerEvent);
					break;
				case PlayerEvent.PLAY:
				case PlayerEvent.PLAYING:
					if ((e.body as int) >= 0) {
						playerEvent = new PlayerEvent(PlayerEvent.PLAY);
						playerEvent.index = e.body as int;
						dispatchEvent(playerEvent);
					}
					break;
				case PlayerEvent.SET_VOLUME:
					playerEvent = new PlayerEvent(PlayerEvent.SET_VOLUME);
					playerEvent.volume = new Number(e.body.toString());
					dispatchEvent(playerEvent);
					break;
				case PlayerEvent.GET_VOLUME:
					//service.post(_playerUI.volume, e.what, e.from, true);
					break;
				case PlayerEvent.PAUSE:
					playerEvent = new PlayerEvent(PlayerEvent.PAUSE);
					dispatchEvent(playerEvent);
					break;
				default:
					break;
			}
		}
		
		private function onConnection(e:ServiceEvent):void {
			timer.stop();
			var e2:ServiceEvent = new ServiceEvent(ServiceEvent.CONNECTED);
			dispatchEvent(e2);
			service.post(null, ServiceEvent.GET_COMP_NAME, null, true);
		}
		
		private function onTimer(e:TimerEvent):void {
			service.connect();
			timer.stop();
		}
		
		private function onLostConnection(e:ServiceEvent):void {
			var e2:ServiceEvent = new ServiceEvent(ServiceEvent.DISCONNECTED);
			dispatchEvent(e2);
			timer.start();
		}
		
		private function onPeerDisconnect(e:ServiceEvent):void {
			if (peerIDToPlayer[e.peerID]) {
				var p:String = peerIDToPlayer[e.peerID];
				if (players.contains(p)) {
					var i:int = players.getItemIndex(p);
					players.removeItemAt(i);
				}
				if (p == _currentPlayer) {
					_currentPlayer = null;
					var e2:ServiceEvent = new ServiceEvent(ServiceEvent.PEER_DISCONNECT);
					dispatchEvent(e2);
				}
			}
		}
		
		//accessed from Player UI
		public function currentTrack():void {
			if (service.isReady)
				service.post(null, PlayerEvent.PLAYING, _currentPlayer, true);
		}

		public function play(e:PlayerEvent):void {
			if (service.isReady)
				service.post(e.index, PlayerEvent.PLAY, _currentPlayer, true);
		}
		
		public function pause(e:PlayerEvent):void {
			if (service.isReady)
				service.post(null, PlayerEvent.PAUSE, _currentPlayer, true);
		}
		
		public function setVolume(e:PlayerEvent):void {
			if (service.isReady)
				service.post(e.volume, PlayerEvent.SET_VOLUME, _currentPlayer, true);
		}

		public function getVolume():void {
			if (service.isReady)
				service.post(null, PlayerEvent.GET_VOLUME, _currentPlayer, true);
		}
		
		public function get isReady():Boolean {
			return service.isReady;
		}
	}
}

class Singleton {}